home *** CD-ROM | disk | FTP | other *** search
- #!/usr/local/bin/perl
- #
- # goform -- crude telnettable Gopher form fillout daemon
- #
- # History:
- # PASR 03/09/93 Original version (release 0.1) by Prentiss Riddle,
- # riddle@rice.edu.
- # PASR 03/29/93 Use CRLF on output to user, to make Macs and PCs happy;
- # explicitly send an IAC WONT ECHO so Mac telnet clients
- # will know that they have to echo locally.
- # PASR 04/02/93 Added "Reply-To" handling. Declared this version 0.2.
- #
- #-------------------------------------------------------------------------
- #
- # INSTALLATION:
- #
- # The goform program should be executed from inetd with the name of the
- # form file as an argument. In order to have multiple goform forms
- # available, each should be assigned a separate port. An example SunOS
- # 4.1.2 installation:
- #
- # Files installed:
- # /foo/cwis/bin/goform executable
- # /foo/cwis/etc/widget.form Widget Request form
- # /foo/cwis/etc/suggest.form Suggestion Box form
- #
- # Added to /etc/services (be sure to make yp afterward):
- # goform10003 10003/tcp # gopher form: widget request
- # goform10004 10004/tcp # gopher form: suggestion box
- #
- # Added to /etc/inetd.conf (be sure to HUP inetd afterward):
- # goform10003 stream tcp nowait nobody /foo/cwis/bin/goform goform /foo/cwis/etc/widget.form
- # goform10004 stream tcp nowait nobody /foo/cwis/bin/goform goform /foo/cwis/etc/suggest.form
- #
- #
- # FORMFILE FORMAT:
- #
- # The first few lines of the formfile specify header lines which will be
- # used to mail off the results after the form is filled out, as follows:
- #
- # To: recipient-address
- # Subject: subject-line
- # Reply-To: return-address
- #
- # The recipient address must be fixed but the subject line and the return
- # address may contain field specifications in the form of a '$' character
- # followed by an integer. These will be expanded to include the
- # user's answers to the correspondingly numbered questions. The Reply-To
- # line is optional; if it is omitted, a "Reply-To:" line will appear in
- # the mail header with no argument. Note that the program doesn't do any
- # error checking of the address specified in the Reply-To field, so
- # recipients should use care in replying.
- #
- # The remainder of the formfile specifies the form to be filled out.
- #
- # Lines containing a '[' are interpreted as questions. Characters following
- # the '[' are taken to be a default value for the answer. Characters
- # preceding the '[' are taken to be a prompt. If there is no prompt
- # preceding the '[', the question is taken to be a running essay questions
- # and multiple lines of input are accepted until a blank line or a line
- # consisting of a single '.' is read.
- #
- # Non-question lines in the formfile are displayed to the user and/or
- # displayed together with the user's answers in the results sent by mail:
- # -- Lines beginning in '>' are displayed to the user but not mailed.
- # -- Lines beginning in '<' are mailed but not displayed to the user.
- # -- Lines beginning in '#' are comments and are ignored.
- # -- Lines containing no '[' and not beginning in '>', '<' or '#' are both
- # displayed to the user and mailed.
- #
- #
- # EXAMPLE FORMFILE:
- #
- # To: widgetmeister@foobar.edu
- # Subject: Widget request from $2 ($1)
- # Reply-To: $1
- # # Test form. This is a comment.
- # WIDGET REQUEST FORM
- # >
- # >Widget Services supplies widgets only to registered students, faculty
- # >and staff of Foobar University.
- # >
- # >To pick up your widget go to Room 101 between the hours of 1-2 pm
- # >Monday through Wednesday.
- #
- # Personal info (e-mail address, name, office address, extension):
- # E-mail address: [
- # Name: [
- # Office address: [
- # Extension: [
- #
- # Widget shape (round, square, triangular -- CHOOSE ONE):
- # Round: [n
- # Square: [n
- # Triangular: [n
- #
- # Number of widgets desired: [1
- #
- # What additional features would you like to see in a widget?
- # [
- #
- # <--------------------------------------------------------------------
- # < FOR OFFICE USE ONLY
- # <
- # < Processed by: ____________________________ Date: ________________
- # <
- # < Comments: _________________________________________________________
- # <--------------------------------------------------------------------
- #
- #-------------------------------------------------------------------------
- # Global variables:
- # $ReplyTo "Reply-To:" line
- # $Subject "Subject:" line
- # $To "To:" line
- # $def are there any default answers in @ans?
- # $formfile name of the file from which form will be taken
- # $mailer mail delivery program
- # $nans number of answers in @ansindex (and possible answers in @ans)
- # $nl number of lines in @lines
- # @ans answers from user (may be predetermined defaults)
- # @ansindex table to look up Nth answer in @ans (since @ans is sparse)
- # @lines lines in form
- # @question array of flags: does this line (in @lines) ask a question?
- # FORM file handle for form file
-
- #-------------------------------------------------------------------------
-
- require("ctime.pl");
-
- $mailer = "/bin/mail";
- $usage = "usage: goform formfile";
-
- # Parse command-line arguments.
- die("$usage\n") unless ($#ARGV == 0);
- $formfile = $ARGV[0];
-
- # Immediately flush all output to STDOUT. Send an "IAC WONT ECHO" string
- # (per RFCs 1184 and 857) so the Mac client will know it has to echo text
- # locally. Then throw away an initial line of input in order to dispose of
- # any remaining telnet protocol cruft.
- $| = 1;
- print("\377\374\001\n"); # IAC WONT ECHO
- print("Press return to begin:\r\n");
- $whatnow = <STDIN>;
- print("\r\n\r\n\r\n\r\n");
-
- &parseform();
-
- do {
- &makepass();
-
- do {
- print("\r\nSave/Cancel/Revise (s/c/r)? ");
- $whatnow = <STDIN>;
- $whatnow =~ tr/A-Z/a-z/;
- } until($whatnow =~ /^\s*(s|save|c|cancel|r|revise)\s*$/);
- if ($whatnow =~ /^\s*(c|cancel)\s*$/) {
- print("Cancelling...")
- &sleep(1);
- exit(0);
- }
- print("\r\n\r\n\r\n\r\n");
- } until ($whatnow =~ /^\s*(s|save)\s*$/);
-
- $Subject = &fixfields($Subject);
- $ReplyTo = &fixfields($ReplyTo);
-
- &sendform();
-
- #-------------------------------------------------------------------------
- # clean -- remove leading and final whitespace from a string.
- #
- # usage: $str = &clean($str);
-
- sub clean {
- local($str) = @_;
- $str =~ s/^\s*//;
- $str =~ s/\s*$//;
- return($str);
- }
- #-------------------------------------------------------------------------
- # fixfields -- fill out "$N" items in Subject and Reply-To lines with
- # corresponding answers
- #
- # Global variables used: $ans $ansindex
-
- sub fixfields {
- local($oldsubj) = @_;
- local($l, $newsubj, $s);
-
- # Step through the Subject line. When you find a "$n", substitute
- # the corresponding answer field.
- $newsubj = $oldsubj;
- while ($newsubj =~ s/\$(\d*)/$ans[$ansindex[$1 - 1]]/e) {
- # do nothing
- }
- return($newsubj);
- }
- #-------------------------------------------------------------------------
- # Make a pass through the form.
- #
- # Global variables used:
-
- sub makepass {
- local($char, $l, $resp);
-
- # # Remind the user how defaults work (unless this is the first
- # # pass and there are none).
- # if ($def) {
- # print("\r\nNOTE:\r\n");
- # print("To accept pre-defined values (in []), press return.\r\n");
- # print("To delete a pre-defined value, type a space.\r\n\r\n");
- # }
- # $def = 1;
-
- # Loop through the lines in the form.
- for ($l = 0; $l < $nl; $l++) {
-
- # Is there a question associated with this line?
- if ($question[$l]) {
- # Do we have a default answer for this question?
- if ($ans[$l]) {
- printf("$lines[$l]<$ans[$l]> ");
- } else {
- print("$lines[$l]");
- }
- # Is this a run-on essay question? (Is there a prompt?)
- if ($lines[$l]) {
- # No, get a single answer.
- $resp = <STDIN>;
- $resp =~ s/[\r\n]*$//;
- $ans[$l] = &clean($resp) if ($resp);
- } else {
- # Yes, it's a run-on question -- accept
- # multiple lines in a single answer.
- print("\r\n") if ($ans[$l]);
- print("(Enter a blank line to finish.)\r\n");
- $resp = <STDIN>;
- $resp =~ s/[\r\n]*$//;
- if ($resp) {
- $ans[$l] = "";
- do {
- $ans[$l] .= &clean($resp) . " ";
- $resp = <STDIN>;
- $resp =~ s/[\r\n]*$//;
- } while ($resp);
- }
- }
- } else {
- # This isn't a question -- print it unless it's
- # intended only for the final mail.
- $char = substr($lines[$l], 0, 1);
- next if ($char eq "<" | $char eq '#');
- if ($char eq ">") {
- print(substr($lines[$l], 1), "\r\n");
- } else {
- print("$lines[$l]\r\n");
- }
- }
- }
- }
- #-------------------------------------------------------------------------
- # mmddyy -- return date in the form "mm/dd/yy"
- #
- # Portability issue: we count on &ctime() to return the date in one of
- # the two following formats:
- #
- # Wed Feb 24 10:42:22 1993
- # Wed Feb 24 10:42:22 CST 1993
- #
- # If it doesn't, we're in trouble...
-
- sub mmddyy {
- local($date, $dd, $mm, $yy);
-
- $date = &ctime(time);
- ($yy) = $date =~ /\s\d\d(\d\d)\s*$/;
- $mm = &monthindex(substr($date, 4, 3));
- $dd = substr($date, 8, 2);
- $dd =~ s/ /0/;
- return("$mm/$dd/$yy");
- }
- #--------------------------------------------------------------------------
- # monthindex -- given a three-character month abbreviation, return the
- # corresponding integer "01" (January) to "12" (December)
- #
- # usage: $mm = &monthindex($monthstr);
- # error: return -1 in case of error;
-
- sub monthindex {
- local($monthstr) = @_;
- local($mm);
- $monthstr =~ tr/A-Z/a-z/;
- $mm = index("janfebmaraprmayjunjulaugsepoctnovdec", $monthstr) / 3 + 1;
- $mm = -1 if ($mm <= 0 || $mm > 12);
- $mm = "0" . $mm if ($mm > 0 && $mm < 10);
- return $mm;
- }
- #-------------------------------------------------------------------------
- # Parse the form.
- #
- # Global variables used: FORM
- # Global variables modified: $ReplyTo $Subject $To $ans $ansindex
- # $def $formfile $nans $nl $lines $question
-
- sub parseform {
- local($_);
-
- open(FORM, "< $formfile") || die("Can't open form $formfile");
-
- $nans = 0;
- $nl = 0;
- $def = 0;
- while ($_ = <FORM>) {
- chop($_);
-
- # Discard comments.
- next if (/^#/);
-
- # Find first instances of header lines.
- if (!$ReplyTo && /^Reply-To:\s+(\S.*)/) {
- $ReplyTo = $1;
- next;
- }
- if (!$Subject && /^Subject:\s+(\S.*)/) {
- $Subject = $1;
- next;
- }
- if (!$To && /^To:\s+(\S.*)/) {
- $To = $1;
- next;
- }
-
- # Determine which lines contain input markers ("[") and of
- # those, which contain predetermined defaults.
- if (/^(.*)\[(.*)\]?$/) {
- $question[$nl] = 1;
- $lines[$nl] = $1;
- $ans[$nl] = $2;
- $ansindex[$nans] = $nl;
- $nans++;
- } else {
- $lines[$nl] = $_;
- }
- $nl++;
- }
- }
- #-------------------------------------------------------------------------
- # sendform -- mail the resulting form off to the recipients defined in the
- # "To:" line.
- #
- # Global variables used: $ReplyTo $Subject $To $ans $lines $mailer $nl
-
- format MAIL =
- ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- $line
- ~~^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
- $line
- .
- sub sendform {
- local($char, $l, $line, $s);
-
- print("Sending...\r\n");
-
- # Open the mail process
- $To =~ s/'//g; # sanitized for your protection
- open(MAIL, "| $mailer '$To'")
- || die("unable to open mailer $mailer to $To");
-
- print(MAIL "Subject: $Subject\r\nReply-To: $ReplyTo\r\n\r\n");
-
- print(MAIL "Date: " . &mmddyy() . "\r\n");
-
- for($l=0; $l<$nl; $l++) {
- # Skip lines intended only for the user.
- $char = substr($lines[$l], 0, 1);
- next if ($char eq ">" | $char eq '#');
- if ($char eq "<") {
- # This line intended only for mail recipient.
- $line = substr($lines[$l], 1);
- } elsif ($lines[$l]) {
- # Normal line -- may include an answer.
- $line = $lines[$l] . $ans[$l];
- } else {
- # Indent lines with no question.
- $line = " " . $ans[$l];
- }
- write(MAIL);
- }
- close(MAIL);
- }
- #-------------------------------------------------------------------------
- # end of goform script
-